home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / libgimp / gimppatheditor.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-11-15  |  14.5 KB  |  480 lines

  1. /* LIBGIMP - The GIMP Library 
  2.  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
  3.  *
  4.  * gimppatheditor.c
  5.  * Copyright (C) 1999 Michael Natterer <mitch@gimp.org>
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2 of the License, or (at your option) any later version.
  11.  * 
  12.  * This library is distributed in the hope that it will be useful, 
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  
  15.  * Library General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the
  19.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20.  * Boston, MA 02111-1307, USA.
  21.  */
  22.  
  23. #include <string.h>
  24.  
  25. #include <gtk/gtk.h>
  26.  
  27. #include "gimppatheditor.h"
  28.  
  29. #include "libgimp/gimpfileselection.h"
  30. #include "libgimp/gimpenv.h"
  31. #include "libgimp/gimpwidgets.h"
  32.  
  33. #include "pixmaps/new.xpm"
  34. #include "pixmaps/delete.xpm"
  35. #include "pixmaps/raise.xpm"
  36. #include "pixmaps/lower.xpm"
  37.  
  38.  
  39. /*  forward declaration  */
  40. static void gimp_path_editor_select_callback   (GtkWidget *widget,
  41.                         gpointer   data);
  42. static void gimp_path_editor_deselect_callback (GtkWidget *widget,
  43.                         gpointer   data);
  44. static void gimp_path_editor_new_callback      (GtkWidget *widget,
  45.                         gpointer   data);
  46. static void gimp_path_editor_move_callback     (GtkWidget *widget,
  47.                         gpointer   data);
  48. static void gimp_path_editor_filesel_callback  (GtkWidget *widget,
  49.                         gpointer   data);
  50. static void gimp_path_editor_delete_callback   (GtkWidget *widget,
  51.                         gpointer   data);
  52.  
  53. enum
  54. {
  55.   PATH_CHANGED,
  56.   LAST_SIGNAL
  57. };
  58.  
  59. static guint gimp_path_editor_signals[LAST_SIGNAL] = { 0 };
  60.  
  61. static GtkVBoxClass *parent_class = NULL;
  62.  
  63. static void
  64. gimp_path_editor_class_init (GimpPathEditorClass *class)
  65. {
  66.   GtkObjectClass *object_class;
  67.  
  68.   object_class = (GtkObjectClass *) class;
  69.  
  70.   parent_class = gtk_type_class (gtk_vbox_get_type ());
  71.  
  72.   gimp_path_editor_signals[PATH_CHANGED] = 
  73.     gtk_signal_new ("path_changed",
  74.             GTK_RUN_FIRST,
  75.             object_class->type,
  76.             GTK_SIGNAL_OFFSET (GimpPathEditorClass,
  77.                        path_changed),
  78.             gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
  79.  
  80.   gtk_object_class_add_signals (object_class, gimp_path_editor_signals, 
  81.                 LAST_SIGNAL);
  82.  
  83.   class->path_changed = NULL;
  84. }
  85.  
  86. static void
  87. gimp_path_editor_init (GimpPathEditor *gpe)
  88. {
  89.   GtkWidget *button_box;
  90.   GtkWidget *button;
  91.   GtkWidget *scrolled_window;
  92.  
  93.   gpe->file_selection  = NULL;
  94.   gpe->selected_item   = NULL;
  95.   gpe->number_of_items = 0;
  96.  
  97.   gpe->upper_hbox = gtk_hbox_new (FALSE, 2);
  98.   gtk_box_pack_start (GTK_BOX (gpe), gpe->upper_hbox, FALSE, TRUE, 0);
  99.   gtk_widget_show (gpe->upper_hbox);
  100.  
  101.   button_box = gtk_hbox_new (TRUE, 0);
  102.   gtk_box_pack_start (GTK_BOX (gpe->upper_hbox), button_box, FALSE, TRUE, 0);
  103.   gtk_widget_show (button_box);
  104.  
  105.   gpe->new_button = button = gimp_pixmap_button_new (new_xpm, NULL);
  106.   gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
  107.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  108.               GTK_SIGNAL_FUNC (gimp_path_editor_new_callback),
  109.               gpe);
  110.   gtk_widget_show (button);
  111.  
  112.   gpe->up_button = button = gimp_pixmap_button_new (raise_xpm, NULL);
  113.   gtk_widget_set_sensitive (button, FALSE);
  114.   gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
  115.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  116.               GTK_SIGNAL_FUNC (gimp_path_editor_move_callback),
  117.               gpe);
  118.   gtk_widget_show (button);
  119.  
  120.   gpe->down_button = button = gimp_pixmap_button_new (lower_xpm, NULL);
  121.   gtk_widget_set_sensitive (button, FALSE);
  122.   gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
  123.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  124.               GTK_SIGNAL_FUNC (gimp_path_editor_move_callback),
  125.               gpe);
  126.   gtk_widget_show (button);
  127.  
  128.   gpe->delete_button = button = gimp_pixmap_button_new (delete_xpm, NULL);
  129.   gtk_widget_set_sensitive (button, FALSE);
  130.   gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
  131.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  132.               GTK_SIGNAL_FUNC (gimp_path_editor_delete_callback),
  133.               gpe);
  134.   gtk_widget_show (button);
  135.  
  136.   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
  137.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
  138.                                   GTK_POLICY_AUTOMATIC,
  139.                                   GTK_POLICY_ALWAYS);
  140.   gtk_box_pack_start (GTK_BOX (gpe), scrolled_window, TRUE, TRUE, 2);
  141.   gtk_widget_show (scrolled_window);
  142.  
  143.   gpe->dir_list = gtk_list_new ();
  144.   gtk_list_set_selection_mode (GTK_LIST (gpe->dir_list), GTK_SELECTION_SINGLE);
  145.   gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window),
  146.                      gpe->dir_list);
  147.   gtk_widget_show (gpe->dir_list);
  148. }
  149.  
  150. GtkType
  151. gimp_path_editor_get_type (void)
  152. {
  153.   static GtkType gpe_type = 0;
  154.  
  155.   if (!gpe_type)
  156.     {
  157.       GtkTypeInfo gpe_info =
  158.       {
  159.     "GimpPathEditor",
  160.     sizeof (GimpPathEditor),
  161.     sizeof (GimpPathEditorClass),
  162.     (GtkClassInitFunc) gimp_path_editor_class_init,
  163.     (GtkObjectInitFunc) gimp_path_editor_init,
  164.     /* reserved_1 */ NULL,
  165.     /* reserved_2 */ NULL,
  166.         (GtkClassInitFunc) NULL
  167.       };
  168.  
  169.       gpe_type = gtk_type_unique (gtk_vbox_get_type (), &gpe_info);
  170.     }
  171.   
  172.   return gpe_type;
  173. }
  174.  
  175. /**
  176.  * gimp_path_editor_new:
  177.  * @filesel_title: The title of the #GtkFileSelection dialog which can be
  178.  *                 popped up by the attached #GimpFileSelection.
  179.  * @path: The initial search path.
  180.  *
  181.  * Creates a new #GimpPathEditor widget.
  182.  *
  183.  * The elements of the initial search path must be separated with the
  184.  * #G_SEARCHPATH_SEPARATOR character.
  185.  *
  186.  * Returns: A pointer to the new #GimpPathEditor widget.
  187.  **/
  188. GtkWidget *
  189. gimp_path_editor_new (const gchar *filesel_title,
  190.               const gchar *path)
  191. {
  192.   GimpPathEditor *gpe;
  193.   GtkWidget      *list_item;
  194.   GList          *directory_list;
  195.   gchar          *directory;
  196.   gchar          *mypath;
  197.  
  198.   g_return_val_if_fail ((filesel_title != NULL), NULL);
  199.   g_return_val_if_fail ((path != NULL), NULL);
  200.  
  201.   gpe = gtk_type_new (gimp_path_editor_get_type ());
  202.  
  203.   gpe->file_selection = gimp_file_selection_new (filesel_title, "", TRUE, TRUE);
  204.   gtk_widget_set_sensitive (gpe->file_selection, FALSE);
  205.   gtk_box_pack_start (GTK_BOX (gpe->upper_hbox), gpe->file_selection,
  206.               TRUE, TRUE, 0);
  207.   gtk_signal_connect (GTK_OBJECT (gpe->file_selection), "filename_changed",
  208.               GTK_SIGNAL_FUNC (gimp_path_editor_filesel_callback),
  209.               gpe);
  210.   gtk_widget_show (gpe->file_selection);
  211.  
  212.   directory_list = NULL;
  213.   directory      = mypath = g_strdup (path);
  214.  
  215.   /*  split up the path  */
  216.   while (strlen (directory))
  217.     {
  218.       gchar *current_dir;
  219.       gchar *next_separator;
  220.  
  221.       next_separator = strchr (directory, G_SEARCHPATH_SEPARATOR);
  222.       if (next_separator != NULL)
  223.     *next_separator = '\0';
  224.  
  225.       current_dir = g_strdup (directory);
  226.       gimp_path_runtime_fix (¤t_dir);
  227.  
  228.       list_item = gtk_list_item_new_with_label (current_dir);
  229.       gtk_object_set_data_full (GTK_OBJECT (list_item), "gimp_path_editor",
  230.                 current_dir,
  231.                 (GtkDestroyNotify) g_free);
  232.       directory_list = g_list_append (directory_list, list_item);
  233.       gtk_signal_connect (GTK_OBJECT (list_item), "select",
  234.               GTK_SIGNAL_FUNC (gimp_path_editor_select_callback),
  235.               gpe);
  236.       gtk_signal_connect (GTK_OBJECT (list_item), "deselect",
  237.               GTK_SIGNAL_FUNC (gimp_path_editor_deselect_callback),
  238.               gpe);
  239.       gtk_widget_show (list_item);
  240.       gpe->number_of_items++;
  241.  
  242.       if (next_separator != NULL)
  243.     directory = next_separator + 1;
  244.       else
  245.     break;
  246.     }
  247.  
  248.   g_free (mypath);
  249.  
  250.   if (directory_list)
  251.     gtk_list_append_items (GTK_LIST (gpe->dir_list), directory_list);
  252.  
  253.   return GTK_WIDGET (gpe);
  254. }
  255.  
  256. /**
  257.  * gimp_path_editor_get_path:
  258.  * @gpe: The path editor you want to get the search path from.
  259.  *
  260.  * The elements of the returned search path string are separated with the
  261.  * #G_SEARCHPATH_SEPARATOR character.
  262.  *
  263.  * Note that you have to g_free() the returned string.
  264.  *
  265.  * Returns: The search path the user has selected in the path editor.
  266.  **/
  267. gchar *
  268. gimp_path_editor_get_path (GimpPathEditor *gpe)
  269. {
  270.   GList *list;
  271.   gchar *path = NULL;
  272.  
  273.   g_return_val_if_fail (gpe != NULL, g_strdup (""));
  274.   g_return_val_if_fail (GIMP_IS_PATH_EDITOR (gpe), g_strdup (""));
  275.  
  276.   for (list = GTK_LIST (gpe->dir_list)->children; list; list = list->next)
  277.     {
  278.       if (path == NULL)
  279.     {
  280.       path =
  281.         g_strdup ((gchar *) gtk_object_get_data (GTK_OBJECT (list->data),
  282.                              "gimp_path_editor"));
  283.     }
  284.       else
  285.     {
  286.       gchar *newpath;
  287.  
  288.       newpath =
  289.         g_strconcat (path,
  290.              G_SEARCHPATH_SEPARATOR_S,
  291.              (gchar *) gtk_object_get_data (GTK_OBJECT (list->data),
  292.                             "gimp_path_editor"),
  293.              NULL);
  294.  
  295.       g_free (path);
  296.       path = newpath;
  297.     }
  298.     }
  299.  
  300.   return path;
  301. }
  302.  
  303. static void
  304. gimp_path_editor_select_callback (GtkWidget *widget,
  305.                   gpointer   data)
  306. {
  307.   GimpPathEditor *gpe;
  308.   gint            pos;
  309.   gchar          *directory;
  310.  
  311.   gpe = GIMP_PATH_EDITOR (data);
  312.   directory = (gchar *) gtk_object_get_data (GTK_OBJECT (widget),
  313.                          "gimp_path_editor");
  314.  
  315.   gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->file_selection), gpe);
  316.   gimp_file_selection_set_filename (GIMP_FILE_SELECTION (gpe->file_selection),
  317.                     directory);
  318.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->file_selection), gpe);
  319.   gpe->selected_item = widget;
  320.  
  321.   pos = gtk_list_child_position (GTK_LIST (gpe->dir_list), gpe->selected_item);
  322.  
  323.   gtk_widget_set_sensitive (gpe->delete_button, TRUE);
  324.   gtk_widget_set_sensitive (gpe->up_button, (pos > 0));
  325.   gtk_widget_set_sensitive (gpe->down_button,
  326.                 (pos < (gpe->number_of_items - 1)));
  327.   gtk_widget_set_sensitive (gpe->file_selection, TRUE);
  328. }
  329.  
  330. /*  the selected directory may never be deselected except by the 'new'
  331.  *  button, so catch the "deselect" signal and reselect it
  332.  */
  333. static void
  334. gimp_path_editor_deselect_callback (GtkWidget *widget,
  335.                     gpointer   data)
  336. {
  337.   GimpPathEditor *gpe;
  338.  
  339.   gpe = GIMP_PATH_EDITOR (data);
  340.  
  341.   if (widget != gpe->selected_item)
  342.     return;
  343.  
  344.   gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  345.   gtk_list_select_child (GTK_LIST (gpe->dir_list), gpe->selected_item);
  346.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  347. }
  348.  
  349. static void
  350. gimp_path_editor_new_callback (GtkWidget *widget,
  351.                    gpointer   data)
  352. {
  353.   GimpPathEditor *gpe;
  354.  
  355.   gpe = GIMP_PATH_EDITOR (data);
  356.  
  357.   if (gpe->selected_item)
  358.     {
  359.       gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  360.       gtk_list_unselect_child (GTK_LIST (gpe->dir_list), gpe->selected_item);
  361.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  362.     }
  363.   gpe->selected_item = NULL;
  364.  
  365.   gtk_widget_set_sensitive (gpe->delete_button, FALSE);
  366.   gtk_widget_set_sensitive (gpe->up_button, FALSE);
  367.   gtk_widget_set_sensitive (gpe->down_button, FALSE);
  368.   gtk_widget_set_sensitive (gpe->file_selection, TRUE);
  369.  
  370.   gtk_editable_set_position
  371.     (GTK_EDITABLE (GIMP_FILE_SELECTION (gpe->file_selection)->entry), -1);
  372.   gtk_widget_grab_focus
  373.     (GTK_WIDGET (GIMP_FILE_SELECTION (gpe->file_selection)->entry));
  374. }
  375.  
  376. static void
  377. gimp_path_editor_move_callback (GtkWidget *widget,
  378.                 gpointer   data)
  379. {
  380.   GimpPathEditor *gpe = GIMP_PATH_EDITOR (data);
  381.   GList          *move_list = NULL;
  382.   gint            pos;
  383.   gint            distance;
  384.  
  385.   if (gpe->selected_item == NULL)
  386.     return;
  387.  
  388.   pos = gtk_list_child_position (GTK_LIST (gpe->dir_list), gpe->selected_item);
  389.   distance = (widget == gpe->up_button) ? - 1 : 1;
  390.   move_list = g_list_append (move_list, gpe->selected_item);
  391.  
  392.   gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  393.   gtk_list_remove_items_no_unref (GTK_LIST (gpe->dir_list), move_list);
  394.   gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->selected_item), gpe);
  395.   gtk_list_insert_items (GTK_LIST (gpe->dir_list), move_list, pos + distance);
  396.   gtk_list_select_item (GTK_LIST (gpe->dir_list), pos + distance);
  397.  
  398.   gtk_signal_emit (GTK_OBJECT (gpe), gimp_path_editor_signals[PATH_CHANGED]);
  399. }
  400.  
  401. static void
  402. gimp_path_editor_delete_callback (GtkWidget *widget,
  403.                   gpointer   data)
  404. {
  405.   GimpPathEditor *gpe = GIMP_PATH_EDITOR (data);
  406.   GList          *delete_list = NULL;
  407.   gint            pos;
  408.  
  409.   if (gpe->selected_item == NULL)
  410.     return;
  411.  
  412.   pos = gtk_list_child_position (GTK_LIST (gpe->dir_list), gpe->selected_item);
  413.   delete_list = g_list_append (delete_list, gpe->selected_item);
  414.  
  415.   gtk_list_remove_items (GTK_LIST (gpe->dir_list), delete_list);
  416.   gpe->number_of_items--;
  417.  
  418.   if (gpe->number_of_items == 0)
  419.     {
  420.       gpe->selected_item = NULL;
  421.       gtk_signal_handler_block_by_data (GTK_OBJECT (gpe->file_selection), gpe);
  422.       gimp_file_selection_set_filename (GIMP_FILE_SELECTION (gpe->file_selection), "");
  423.       gtk_signal_handler_unblock_by_data (GTK_OBJECT (gpe->file_selection), gpe);
  424.       gtk_widget_set_sensitive (gpe->delete_button, FALSE);
  425.       gtk_widget_set_sensitive (gpe->file_selection, FALSE);
  426.  
  427.       return;
  428.     }
  429.  
  430.   if ((pos == gpe->number_of_items) && (pos > 0))
  431.     pos--;
  432.   gtk_list_select_item (GTK_LIST (gpe->dir_list), pos);
  433.  
  434.   gtk_signal_emit (GTK_OBJECT (gpe), gimp_path_editor_signals[PATH_CHANGED]);
  435. }
  436.  
  437. static void
  438. gimp_path_editor_filesel_callback (GtkWidget *widget,
  439.                    gpointer   data)
  440. {
  441.   GimpPathEditor *gpe = GIMP_PATH_EDITOR (data);
  442.   GList          *append_list = NULL;
  443.   GtkWidget      *list_item = NULL;
  444.   gchar          *directory;
  445.  
  446.   directory = gimp_file_selection_get_filename (GIMP_FILE_SELECTION (widget));
  447.   if (strcmp (directory, "") == 0)
  448.     return;
  449.  
  450.   if (gpe->selected_item == NULL)
  451.     {
  452.       list_item = gtk_list_item_new_with_label (directory);
  453.       gtk_object_set_data_full (GTK_OBJECT (list_item), "gimp_path_editor",
  454.                 directory,
  455.                 (GtkDestroyNotify) g_free);
  456.       append_list = g_list_append (append_list, list_item);
  457.       gtk_signal_connect (GTK_OBJECT (list_item), "select",
  458.               GTK_SIGNAL_FUNC (gimp_path_editor_select_callback),
  459.               gpe);
  460.       gtk_signal_connect (GTK_OBJECT (list_item), "deselect",
  461.               GTK_SIGNAL_FUNC (gimp_path_editor_deselect_callback),
  462.               gpe);
  463.       gtk_widget_show (list_item);
  464.       gpe->number_of_items++;
  465.       gtk_list_append_items (GTK_LIST (gpe->dir_list), append_list);
  466.       gtk_list_select_item (GTK_LIST (gpe->dir_list), gpe->number_of_items - 1);
  467.     }
  468.   else
  469.     {
  470.       gtk_label_set_text (GTK_LABEL (GTK_BIN (gpe->selected_item)->child),
  471.               directory);
  472.       gtk_object_set_data_full (GTK_OBJECT (gpe->selected_item),
  473.                 "gimp_path_editor",
  474.                 directory,
  475.                 (GtkDestroyNotify) g_free);
  476.     }
  477.  
  478.   gtk_signal_emit (GTK_OBJECT (gpe), gimp_path_editor_signals[PATH_CHANGED]);
  479. }
  480.